#ifndef RENDERER3D_H
#define RENDERER3D_H

#include "Renderer/orthographicCamera.h"

#include "Renderer/texture.h"

#include "Renderer/camera.h"
// #include "Renderer/EditorCamera.h"

#include "Scene/Components.h"
#include "Core/base.h"
#include "Renderer/rendererAPI.h"
#include "Renderer/framebuffer.h"

namespace CC
{

	class CC_EXPORT Renderer3D
	{
	public:
		static void Init();
		static void Shutdown();

		static void BeginScene(Camera *camera, const glm::mat4 &transform = glm::mat4(1.0), Framebuffer* framebuffer = nullptr, bool debugPhysics = false, std::string renderPass = "");
		static void EndScene();
		static void Flush();

		// Primitives
		static void DrawCube(const glm::vec3 &position, const glm::vec3 &rotation, const glm::vec3 &size, const glm::vec4 &color, int entityID = -1);
		static void DrawCube(const glm::mat4 &transform, const glm::vec4 &color, int entityID = -1);

		static void DrawCube(const glm::vec3 &position, const glm::vec3 &rotation, const glm::vec3 &size, Texture2D *texture, float tilingFactor = 1.0f, const glm::vec4 &tintColor = glm::vec4(1.0f));
		static void DrawCube(const glm::mat4 &transform, Texture2D *texture, float tilingFactor = 1.0f, const glm::vec4 &tintColor = glm::vec4(1.0f), int entityID = -1);
		
		static void DrawSprite(const glm::mat4 &transform, MeshBasicMaterialComponent &src, int entityID);
		static void DrawModel(const glm::mat4 &transform, MeshModelMaterialComponent &src, MeshComponent &mesh, int entityID = -1);
		static void DrawModelCustomShader(const glm::mat4 &transform, MeshModelMaterialComponent &src, MeshComponent &mesh, ShaderComponent& shaderc, Entity* entity);
		static void DrawModelNoAnim(const glm::mat4 &transform, MeshModelMaterialComponent &src, MeshComponent &mesh, int entityID = -1);
		static void DrawModelNoAnimCustomShader(const glm::mat4 &transform, MeshModelMaterialComponent &src, MeshComponent &mesh, ShaderComponent& shaderc, Entity* entity);
		static void DrawModelAnim(const glm::mat4 &transform, MeshModelMaterialComponent &src, MeshComponent &mesh, AnimationComponent &anim, int entityID = -1);
		static void DrawModelAnimCustomShader(const glm::mat4 &transform, MeshModelMaterialComponent &src, MeshComponent &mesh, AnimationComponent &anim, ShaderComponent& shaderc, Entity* entity);
	
		static void DrawBoxBorder(const glm::vec3 &position, const glm::vec3 &rotation, const glm::vec3 &size, glm::vec4 &color = glm::vec4(1.0)); // Debug
		static void DrawBoxBorder(const glm::mat4 &transform, glm::vec4 &color = glm::vec4(1.0)); // Debug
		//static void DrawTriangleBorder(const glm::vec3 &position, const glm::vec3 &rotation, 
  //          const unsigned char* vertexBase, const int vertexStride, const int numVertices,
  //          const unsigned char* triangleIndexBase, const int triangleIndexStride, const int numTriangles,
  //          glm::vec4 &color = glm::vec4(1.0)); // Debug

        static void DrawTriangleBorder(const glm::mat4 &transform, MeshModelMaterialComponent &src, MeshComponent &mesh, int entityID = -1); // Debug

		static float GetLineWidth();
		static void SetLineWidth(float width);
		static void DrawLine(const glm::vec3 &start, const glm::vec3 &end, const glm::vec4 &color = glm::vec4(1.0), int entityID = -1);

		static void DrawSkybox(const glm::mat4 &transform, const MeshCubeMaterialComponent &src, int entityID = -1);

		static void SetDisplayMode(DisplayModesEnum mode);

		static void OnViewportResize(uint32_t x, uint32_t y, uint32_t width, uint32_t height);

		static void SetLightPos(const glm::vec4 &pos) { m_LightPos = pos; }
		static glm::vec4 GetLightPos() { return m_LightPos; }

        static void SetLightColor(const glm::vec4 &v) { m_LightColor = v; }
        static glm::vec4 GetLightColor() { return m_LightColor; }

        static void SetLightIntensity(const float &v) { m_LightIntensity = v; }
        static float GetLightIntensity() { return m_LightIntensity; }

		static Texture2D* GetDepthAttachmentTexture2D();
		static Texture2D* GetColor0AttachmentTexture2D();

        static Texture2D* GetTransparentDepthAttachmentTexture2D();
        static Texture2D* GetTransparentColor0AttachmentTexture2D();

        static Texture2D* GetCustomDepthAttachmentTexture2D();
        static Texture2D* GetCustomColor0AttachmentTexture2D();

		static void SetShadowDrawState(bool s);

		static FramebufferSpecification GetSpecification();

		// Stats
		struct Statistics
		{
			uint32_t DrawCalls = 0;
			uint32_t QuadCount = 0;
			uint32_t TriangleCount = 0;

			uint32_t GetTotalVertexCount() const { return QuadCount * 8 + TriangleCount * 3; }
			uint32_t GetTotalIndexCount() const { return QuadCount * 36 + TriangleCount * 3; }
		};
		static void ResetStats();
		static Statistics GetStats();

	private:
		static void StartBatch();
		static void NextBatch();

	private:
		static glm::vec4 m_LightPos;
		static glm::vec4 m_LightColor;
        static float m_LightIntensity;
		static uint32_t m_ViewportWidth;
		static uint32_t m_ViewportHeight;
        static glm::mat4 m_depthBiasMVP;
        static glm::mat4 m_depthMVP;
	};	

}

#endif